#if __MOSS__

using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls;
using aspnetwebparts = System.Web.UI.WebControls.WebParts;

using Microsoft.SharePoint;
using Microsoft.SharePoint.Portal;
using wsswebparts = Microsoft.SharePoint.WebPartPages;
using mosswebparts = Microsoft.SharePoint.Portal.WebControls;

using Behemoth.SharePoint;
using Behemoth.SharePoint.Logging;

namespace Behemoth.SharePoint.WebParts {
  [Guid("3c4fd832-11e7-4b68-a84c-ca7b088603aa")]
  public class FlexQueryStringFilter : mosswebparts.ContextFilterWebPart /* wsswebparts.WebPart */, wsswebparts.ITransformableFilterValues {

    private const string __ParameterName = "SubPart";

    private ErrorBag _errors = new ErrorBag();
    private ULSTraceLogging _log = new ULSTraceLogging();

    public FlexQueryStringFilter() {
      this.ExportMode = aspnetwebparts.WebPartExportMode.All;
    }

    #region ITransformableFilterValues implementation

    // Implementations of the ITransformableFilterValues properties.
    [wsswebparts.WebPartStorage(wsswebparts.Storage.None)]
    public override bool AllowMultipleValues {
      get {
        return true;
      }
    }

    [wsswebparts.WebPartStorage(wsswebparts.Storage.None)]
    public override bool AllowAllValue {
      get {
        return true;
      }
    }

    [wsswebparts.WebPartStorage(wsswebparts.Storage.None)]
    public override bool AllowEmptyValue {
      get {
        return true;
      }
    }

    /* Use the default name provided by the base class
    [wsswebparts.WebPartStorage(wsswebparts.Storage.None)]
    public override string ParameterName {
      get {
        return __ParameterName;
      }
    }
     */

    [wsswebparts.WebPartStorage(wsswebparts.Storage.None)]
    public override ReadOnlyCollection<string> ParameterValues {
      get {
        string[] values = GetSubPartItemValue();
        return values == null ?
            null :
            new ReadOnlyCollection<string>(values);
      }
    }

    /*
    // Use the ConnectionProvider attribute to specify the method that
    // the Web Part framework should call to allow us to return an instance
    // of our ITransformableFilterValues interface.
    [aspnetwebparts.ConnectionProvider(__ParameterName,
     "QueryStringSubPartFilterValues", AllowsMultipleConnections = true)]
    public wsswebparts.ITransformableFilterValues
    SetConnectionInterface() {
      return this;
    }
     */

    #endregion

    #region Web Part Properties

    [aspnetwebparts.Personalizable(aspnetwebparts.PersonalizationScope.Shared)]
    [aspnetwebparts.WebBrowsable(true)]
    [System.ComponentModel.Category("Query Split Options")]
    [aspnetwebparts.WebDisplayName("Query String Parameter Name")]
    [aspnetwebparts.WebDescription("The query string parameter whose value(s) will be extracted.")]

    [wsswebparts.WebPartStorage(wsswebparts.Storage.Shared)]
    [wsswebparts.SPWebCategoryName("Query Split Options")]
    [Browsable(true)]
    [DisplayName("Query String Parameter Name")]
    [Description("The query string parameter whose value(s) will be extracted.")]
    public string QueryStringParameterName {
      get {
        return _QueryStringParameterName;
      }
      set { _QueryStringParameterName = value; }
    }
    private string _QueryStringParameterName;

    [aspnetwebparts.Personalizable(aspnetwebparts.PersonalizationScope.Shared)]
    [aspnetwebparts.WebBrowsable(true)]
    [System.ComponentModel.Category("Query Split Options")]
    [aspnetwebparts.WebDisplayName("Splitter Text")]
    [aspnetwebparts.WebDescription("The character or string used to split a query parameter into its individual arguments.")]

    [wsswebparts.WebPartStorage(wsswebparts.Storage.Shared)]
    [wsswebparts.SPWebCategoryName("Query Split Options")]
    [Browsable(true)]
    [DisplayName("Splitter Text")]
    [Description("The character or string used to split a query parameter into its individual arguments.")]
    public string SplitterText {
      get {
        return _SplitterText;
      }
      set { _SplitterText = value; }
    }
    private string _SplitterText = " ";

    [aspnetwebparts.Personalizable(aspnetwebparts.PersonalizationScope.Shared)]
    [aspnetwebparts.WebBrowsable(true)]
    [System.ComponentModel.Category("Query Split Options")]
    [aspnetwebparts.WebDisplayName("Sub-Part Parameter Name")]
    [aspnetwebparts.WebDescription("The key text for the desired argument (sub-part) whose value will be extracted.")]

    [wsswebparts.WebPartStorage(wsswebparts.Storage.Shared)]
    [wsswebparts.SPWebCategoryName("Query Split Options")]
    [Browsable(true)]
    [DisplayName("Sub-Part Parameter Name")]
    [Description("The key text for the desired argument (sub-part) whose value will be extracted.")]
    public string SubPartParameterName {
      get {
        return _SubPartParameterName;
      }
      set { _SubPartParameterName = value; }
    }
    private string _SubPartParameterName;

    [aspnetwebparts.Personalizable(aspnetwebparts.PersonalizationScope.Shared)]
    [aspnetwebparts.WebBrowsable(true)]
    [System.ComponentModel.Category("Query Split Options")]
    [aspnetwebparts.WebDisplayName("Delimiter Text")]
    [aspnetwebparts.WebDescription("The character or string used to split an argument (sub-part) into a key-value pair.")]

    [wsswebparts.WebPartStorage(wsswebparts.Storage.Shared)]
    [wsswebparts.SPWebCategoryName("Query Split Options")]
    [Browsable(true)]
    [DisplayName("Delimiter Text")]
    [Description("The character or string used to split an argument (sub-part) into a key-value pair.")]
    public string DelimiterText {
      get {
        return _DelimiterText;
      }
      set { _DelimiterText = value; }
    }
    private string _DelimiterText = ":";

    [aspnetwebparts.Personalizable(aspnetwebparts.PersonalizationScope.Shared)]
    [aspnetwebparts.WebBrowsable(true)]
    [System.ComponentModel.Category("Query Split Options")]
    [aspnetwebparts.WebDisplayName("Default Value")]
    [aspnetwebparts.WebDescription("The value that will be provided if the parameter or sub-part can not be extracted.")]

    [wsswebparts.WebPartStorage(wsswebparts.Storage.Shared)]
    [wsswebparts.SPWebCategoryName("Query Split Options")]
    [Browsable(true)]
    [DisplayName("Default Value")]
    [Description("The value that will be provided if the parameter or sub-part can not be extracted.")]
    public string DefaultValue {
      get {
        return _DefaultValue;
      }
      set { _DefaultValue = value; }
    }
    private string _DefaultValue;

    [aspnetwebparts.Personalizable(aspnetwebparts.PersonalizationScope.Shared)]
    [aspnetwebparts.WebBrowsable(true)]
    [System.ComponentModel.Category("Query Split Options")]
    [aspnetwebparts.WebDisplayName("Provide Default Value for None")]
    [aspnetwebparts.WebDescription("Send Default Value if there are no values")]

    [wsswebparts.WebPartStorage(wsswebparts.Storage.Shared)]
    [wsswebparts.SPWebCategoryName("Query Split Options")]
    [Browsable(true)]
    [DisplayName("Provide Default Value for None")]
    [Description("Send Default Value if there are no values")]
    public bool ProvideDefaultValue {
      get {
        return _ProvideDefaultValue;
      }
      set { _ProvideDefaultValue = value; }
    }
    private bool _ProvideDefaultValue = true;

    #endregion

    private IList<string> argList;

    protected override string[] GetRawFilterValues() {
      return GetSubPartItemValue();
    }

    public string[] GetSubParts() {
      this.argList = null;
      try {
        if (string.IsNullOrEmpty(this.SplitterText))
          throw new Exception("You must provide a value for Splitter Text.");

        string qValue = GetParameter();
        if (qValue == null)
          return GetNullOrDefault();

        this.argList = Parser.SplitString(qValue, this.SplitterText);
        if (argList.Count <= 0)
          return GetNullOrDefault();

        string[] retValues = new string[argList.Count];
        argList.CopyTo(retValues, 0);
        return retValues;

      } catch (Exception ex) {
        HandleError("Exception occurred in GetRawFilterValues()", ex, true);
        return GetNullOrDefault();
      }
    }

    public string[] GetSubPartItemValue() {
      try {
        string[] retVal = GetSubParts(); // also sets this.argList
        if (argList == null || argList.Count <= 0 || this.ReturnAllSubparts)
          return retVal;

        if (string.IsNullOrEmpty(this.DelimiterText))
          throw new Exception("You must provide a value for Delimiter Text.");
        NameValueCollection argCollection = Parser.CreateParameterCollection(this.argList, this.DelimiterText, true);

        string[] retVal2 = new string[1];
        retVal2[0] = argCollection[this.SubPartParameterName];
        if (retVal2[0] == null)
          return GetNullOrDefault();
        else
          return retVal2;
      } catch (Exception ex) {
        HandleError("Exception occurred in GetSubPartData()", ex, true);
        return GetNullOrDefault();
      }
    }

    private string[] GetNullOrDefault() {
      return (ProvideDefaultValue) ? new string[] { DefaultValue } : null;
    }

    private string GetParameter() {
      string qValue = string.Empty;
      NameValueCollection q = this.Page.Request.QueryString;
      if (q[this.QueryStringParameterName] == null)
        return string.Empty;
      qValue = q[this.QueryStringParameterName];
      return qValue;
    }

    protected override void RenderContents(HtmlTextWriter output) {
      this.EnsureChildControls();
      RenderChildren(output);
    }

    protected override void Render(HtmlTextWriter writer) {
      // output any errors, warnings, or info messages that may have been added.
      _errors.Render(writer);
      // if there was an error don't attempt to render the form itself
      if (this._errors.HasErrors)
        return;
      else
        base.Render(writer);
    }    

    // TODO call intenral method here
    protected override string DesignTimeHtml {
      get {
        return "<p>This context filter web part is only visible in Edit Page Mode.</p>";
        //return mosswebparts.WCUtil.Text(false, LocStringId.QueryStringFilterWebPart_EditModeMessage, new object[] { this.QueryStringParameterName });
      }
    }

    public bool ReturnAllSubparts {
      get {
        return string.IsNullOrEmpty(this.SubPartParameterName);
      }
    }

    private void HandleError(string msg, Exception ex, bool isError) {
      if (isError || ex != null) {
        _errors.AddError(msg);
        _errors.AddError(ex);
      } else {
        _errors.AddWarning(msg);
      }
      _log.Write(msg, isError ? TraceSeverity.Unexpected : TraceSeverity.WarningEvent);
      if (ex != null)
        _log.Write(ex);
    }

  } // class
} // namespace

#endif